#ifndef MSGQUEUE_H
#define MSGQUEUE_H

#include <cmsis_os.h>
#include <units.h>
using namespace units::literals;

namespace os {
/**
 * @brief 消息队列
 * @tparam T 消息类型
 * @tparam length 消息队列最大长度
 */
template <typename T = uint8_t, size_t length = 5>
class MsgQueue {
    static_assert(length > 0, "length must be greater than 0");

    /**
     * @brief Make the buffer the first element of MsgQueue for easy memory alignment
     */
    [[gnu::aligned(4)]] uint8_t buffer_[sizeof(T) * length]{};

    /**
     * @brief FreeRTOS的消息队列句柄
     */
    QueueHandle_t hQueue_;
    StaticQueue_t xStaticQueue_{};

   public:
    MsgQueue() {
        hQueue_ = xQueueCreateStatic(length, sizeof(T), buffer_, &xStaticQueue_);
        os_assert(hQueue_ != nullptr, "creat queue failed");
    };
    ~MsgQueue() { vQueueDelete(hQueue_); }

    /**
     * @brief 向队列发送一条消息
     * @param msg 指向消息的指针
     * @param waitTime_ms 队列满最大阻塞时间，默认永久阻塞
     * @return true-发送成功；false-发送失败
     */
    [[nodiscard]] bool send(T* msg, units::time::millisecond_t const waitTime_ms =
                                        units::make_unit<units::time::millisecond_t>(portMAX_DELAY)) {
        return xQueueSend(hQueue_, reinterpret_cast<void*>(msg), waitTime_ms.to<uint32_t>());
    }

    /**
     * @brief 从中断中向队列发送一条消息
     * @param msg 指向消息的指针
     * @return true-发送成功；false-发送失败
     */
    [[nodiscard]] bool sendFromISR(T* msg) { return xQueueSendFromISR(hQueue_, reinterpret_cast<void*>(msg), NULL); }

    /**
     * @brief 防呆接口，向队列发送一条消息
     * @param msg 指向消息的指针
     * @return true-发送成功；false-发送失败
     */
    [[nodiscard]] bool sendSafe(T* msg) {
        if (xPortIsInsideInterrupt()) {
            return SendFromISR(msg);
        }
        return Send(msg);
    }

    /**
     * @brief 向队列发送一条消息，填在队首
     * @param msg 指向消息的指针
     * @param waitTime_ms 队列满最大阻塞时间，默认永久阻塞
     * @return true-发送成功；false-发送失败
     */
    [[nodiscard]] bool send2Front(T* msg, units::time::millisecond_t const waitTime_ms =
                                              units::make_unit<units::time::millisecond_t>(portMAX_DELAY)) {
        return xQueueSendToFront(hQueue_, reinterpret_cast<void*>(msg), waitTime_ms.to<uint32_t>());
    }

    /**
     * @brief 从中断中向队列发送一条消息，消息填在队首
     * @param msg 指向消息的指针
     * @return true-发送成功；false-发送失败
     */
    [[nodiscard]] bool send2FrontFromISR(T* msg) {
        return xQueueSendToFrontFromISR(hQueue_, reinterpret_cast<void*>(msg), NULL);
    }

    /**
     * @brief 防呆接口，向队列发送一条消息，消息填在队首
     * @param msg 指向消息的指针
     * @return true-发送成功；false-发送失败
     */
    [[nodiscard]] bool send2FrontSafe(T* msg) {
        if (xPortIsInsideInterrupt()) {
            return Send2FrontFromISR(msg);
        }
        return Send2Front(msg);
    }

    /**
     * @brief 从队列接收一条消息
     * @param msg 用于接收消息的内存地址
     * @param waitTime_ms 队列空最大阻塞时间
     * @return true-成功；false-失败
     */
    [[nodiscard]] bool receiveTo(T* msg, units::time::millisecond_t const waitTime_ms =
                                             units::make_unit<units::time::millisecond_t>(portMAX_DELAY)) {
        return xQueueReceive(hQueue_, reinterpret_cast<void*>(msg), waitTime_ms.to<uint32_t>());
    }

    /**
     * @brief 在中断中从队列接收一条消息
     * @param msg 用于接收消息的内存地址
     * @return true-成功；false-失败
     */
    [[nodiscard]] bool receiveToFromISR(T* msg) {
        return xQueueReceiveFromISR(hQueue_, reinterpret_cast<void*>(msg), NULL);
    }

    /**
     * @brief 防呆接口，从队列中接收一条消息
     * @param msg 用于接收消息的内存地址
     * @return true-成功；false-失败
     */
    [[nodiscard]] bool receiveToSafe(T* msg) {
        if (xPortIsInsideInterrupt()) {
            return ReceiveToFromISR(msg);
        }
        return ReceiveTo(msg, 0_ms);
    }

    /**
     * @brief 从队列中查看一条消息，但不移除它
     * @param msg 用于接收消息的内存地址
     * @param waitTime_ms 队列空最大阻塞时间
     * @return true-成功；false-失败
     */
    [[nodiscard]] bool peek(T* msg, units::time::millisecond_t const waitTime_ms =
                                        units::make_unit<units::time::millisecond_t>(portMAX_DELAY)) {
        return xQueuePeek(hQueue_, reinterpret_cast<void*>(msg), waitTime_ms.to<uint32_t>());
    }

    /**
     * @brief 在中断中从队列中查看一条消息，但不移除它
     * @param msg 用于接收消息的内存地址
     * @return true-成功；false-失败
     */
    [[nodiscard]] bool peekFromISR(T* msg) { return xQueuePeekFromISR(hQueue_, reinterpret_cast<void*>(msg)); }

    /**
     * @brief 防呆接口，从队列中查看一条消息，但不移除它
     * @param msg 用于接收消息的内存地址
     * @return true-成功；false-失败
     */
    [[nodiscard]] bool peekSafe(T* msg) {
        if (xPortIsInsideInterrupt()) {
            return PeekFromISR(msg);
        }
        return Peek(msg);
    }

    /**
     * @brief 清空队列
     * @return true-成功；false-失败
     */
    [[nodiscard]] bool reset() const { return xQueueReset(hQueue_); }

    /**
     * @brief 获取FreeRTOS队列句柄
     * @return 队列句柄
     */
    [[nodiscard]] QueueHandle_t get_hQueue() const { return hQueue_; }

    MsgQueue(MsgQueue const&) = delete;

    MsgQueue(MsgQueue&&) = delete;
};
}  // namespace os

#endif  // MSGQUEUE_H
